/**
 * DATABASE SYSTEMS IMPLEMENTATION - PROJECT 2
 * STAGE 2 - CODE SUBMISSION
 * 
 * AUTHORS:
 * NEHA SRIVASTAVA NS2724
 * TANAY TANDON  TT2382
 * 
 * 
 * DEPARTMENT OF COMPUTER SCIENCE,
 * COLUMBIA UNIVERSITY, 2011
 */
package algorithm;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;



/**
 * @author Neha
 * This class defines the data structure to store the 
 * information for each subset used in the Algorithm
 * 
 */
public class Node {

	/**
	 * Let S denote the set of basic terms, and let k
	 * be the cardinality of S.
	 * Create an array A[] of size 2k indexed by the subsets of S. 
	 * The array elements are records containing: 
	 * The number n of basic terms in the 
	 * corresponding subset;
	 * The product p of the selectivities of all terms in the subset;
	 * A bit b determining whether the no-branch optimization was used to get the best cost, 
	 * initialized to 0;
	 * The current best cost c for the subset; 
	 * The left child L and right child R of the  sub-plans giving the best cost. 
	 * L and R range over indexes for A[], and are initialized to null;.
	 */
	
	  int n; // number of terms
	  double p; // product of selectivities
	  int b=0; //(Indicating a bit)
	  boolean bit=false;
	  double c; // cost of the plan with that subset
	  int L=-1; // index of left child
	  int R=-1; // index of right child
	  public ArrayList<Double> terms = new ArrayList<Double>();
	  public HashMap<Double,Double> names= new HashMap<Double, Double>(); // The first element (key) is the name of element
	  																	// The second element is the term itself
	

	  /**
	   * @param p : product of selectivities of the terms
	   * @param c : cost function
	   * @param b : bit to store if no-branch optimization was enabled 
	   * @param L : index of the left node
	   * @param R : index of the right node
	   * @param terms : List of terms in the node
	   */
	  
	  public Node(){
		  terms = new ArrayList<Double>();
		  p=1;
	}
	  
	 public Node( double c,	ArrayList<Double> terms) {
			super();
			this.terms = terms;
			this.n = terms.size();
			this.p = 1;
			this.b = 0;
			this.bit = false;
			this.c = c;
		}
		
	 /**
	 * @return the terms
	 */
	public ArrayList<Double> getTerms() {
		return terms;
	}

	/**
	 * @param terms the terms to set
	 */
	public void setTerms(ArrayList<Double> terms) {
		this.terms = terms;
	}


	/**
	 * @return the n
	 */
	public int getN() {
		return n;
	}

	/**
	 * @return the p
	 */
	public double getP() {
		return p;
	}

	/**
	 * @return the b
	 */
	public int getB() {
		return b;
	}

	/**
	 * @return the bit
	 */
	public boolean isBit() {
		return bit;
	}

	/**
	 * @return the c
	 */
	public double getC() {
		return this.c;
	}

	/**
	 * @return the l
	 */
	public int getL() {
		return L;
	}

	/**
	 * @return the r
	 */
	public int getR() {
		return R;
	}

	  /**
	 * @param b the b to set
	 */
	public void setB(int b) {
		this.b = b;
	}

	/**
	 * @param bit the bit to set
	 */
	public void setBit(boolean bit) {
		this.bit = bit;
	}

	/**
	 * @param l the l to set
	 */
	public void setL(int l) {
		L = l;
	}

	/**
	 * @param r the r to set
	 */
	public void setR(int r) {
		R = r;
	}
	
	public void calculateCost(double r, double t,double l, double m, double a, double f)
	{
		double q;
		
		q= p<=0.5 ? p: 1-p;
		
		double noBranchCost=0.0;
		double logBranchCost=0.0;
		noBranchCost= n*r+ (n-1)*l+ f*n+a;
		logBranchCost=n*r+ (n-1)*l+ f*n+t+ m*q+ p*a;
		
		if(noBranchCost<logBranchCost)
		{ 
			c=noBranchCost;
			b=1;
			bit=true;
		}
		else
		{
			c= logBranchCost;
			b=0;
			bit=false;
		}
		
	}
	
	/**
	 * @param c the c to set
	 */
	public void setC(double c) {
		this.c = c;
	}

	public void calculateP()
	{
	
		Iterator <Double> it= terms.iterator();
		n= terms.size();
		while(it.hasNext())
		{
			p*=it.next();
		}
	
	}
	
	public void initNameHash()
	{
		Iterator <Double> it= terms.iterator();
		double tempVar;
		double tempName;
		
		
		//ASSIGNING UNIQUE NAMES TO VALUES, ADDING A NEW NAME IF DUPLICATES EXIST
		while(it.hasNext())
		{
			tempVar= it.next();
			tempName=tempVar;
			while(names.containsKey(tempName))
			{
				tempName=tempName+0.001;
			}
			names.put(tempName, tempVar);
		}
	}
	
	public double lookUpTermForName(double name)
	{
		return names.get(name);
	}
	
	
	
	public String printAll()
	{
		Iterator<Double> it= this.names.keySet().iterator();
		String temp= "";
		int l=terms.size();
		double currentTerm;
		int st=0;
		if(l==1)
		{
			st=Main.lookUpMap.get(it.next());
			temp+="t"+st+"[o"+st+"[i]]";
		}
		else{
			temp+="(";
			while(it.hasNext())
			{
				
					l--;
					currentTerm=it.next();
					if(l!=0)
					{
					st=Main.lookUpMap.get(currentTerm);
					temp+= "t"+st+"[o"+st+"[i]] & ";
					}
					else
					{
						st=Main.lookUpMap.get(currentTerm);
						temp+="t"+st+"[o"+st+"[i]]";
					}
					
				
			}
			temp+=")";
		}
		
		
		return temp;
		
		
	}
	
	public static void main(String[] args) {
		/* TODO: Create a data structure, that stores all the information
		calculating methods c-metric, d-metric.
		*/
	}
	
	
}
